package vg.services.graph_view_manager.realization.graph_view.smart_graph_view.realization;

import java.awt.Color;
import java.util.Collection;
import java.util.Map;
import java.util.Observer;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;

import org.apache.commons.lang.mutable.MutableBoolean;

import vg.services.data_base_manager.data.graph.Attribute;
import vg.services.data_base_manager.data.graph.Edge;
import vg.services.data_base_manager.data.graph.Graph;
import vg.services.data_base_manager.data.graph.Vertex;
import vg.services.graph_view_manager.interfaces.graph_view.AGraphView;
import vg.services.graph_view_manager.interfaces.graph_view.graph_lib_depending.AMainGraphComponent;
import vg.services.graph_view_manager.realization.graph_view.smart_graph_view.interfaces.ISGVGraphView4Patching;
import vg.services.graph_view_manager.realization.graph_view.smart_graph_view.realization.renderers.JGraphRenderer;
import vg.services.main_manager.MainManager;

/**
 * Implementation of ISGVGraphView4Patching.
 * @author Timur Zolotuhin (e-mail: tzolotuhin@gmail.com)
 */
public class SGVGraphView4Patching implements ISGVGraphView4Patching {
	// Main components
	private AGraphView parent;
	private JGraphRenderer sgv_graph_renderer; // contains components for rendering of graph
	
	/**
	 * Constructor.
	 */
	public SGVGraphView4Patching(AGraphView parent) {
		this.parent = parent;
		
		init_components();
	}
	
	public void merge(final SGVGraphView4Patching src_sgv_graph_view4patching, final Graph src_graph) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						merge(src_sgv_graph_view4patching, src_graph);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.merge(src_sgv_graph_view4patching.sgv_graph_renderer, src_graph);
		}				
	}

//=============================================================================
//-----------------Methods for getting different views-------------------------
	@Override
	public JComponent getView() {
		return sgv_graph_renderer.getView();
	}
	
	@Override
	public JComponent getMiniMap() {
		return sgv_graph_renderer.getMiniMap();
	}
	
	@Override
	public void refreshView() {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						refreshView();
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.refreshView();
		}		
	}
	
//=============================================================================
//-----------------Methods for getting information about graph elements--------	
	@Override
	public Map<Vertex, Map<Attribute, MutableBoolean>> getAllVerticesInfo() {
		return sgv_graph_renderer.getAllVerticesInfo();
	}
	
	@Override
	public Map<Edge, Map<Attribute, MutableBoolean>> getAllEdgesInfo() {
		return sgv_graph_renderer.getAllEdgesInfo();
	}
	
	@Override
	public Map<Vertex, Map<Attribute, MutableBoolean>> getSelectionVerticesInfo() {
		return sgv_graph_renderer.getSelectionVerticesInfo();
	}
	
	@Override
	public Map<Edge, Map<Attribute, MutableBoolean>> getSelectionEdgesInfo() {
		return sgv_graph_renderer.getSelectionEdgesInfo();
	}
	
	@Override
	public Graph getGraph() {
		return sgv_graph_renderer.getGraph();
	}
	
	@Override
	public Graph getSelectionSubGraph() {
		return sgv_graph_renderer.getSelectionSubGraph();
	}

//=============================================================================
//-----------------Methods for changing visualization from elements------------
	@Override
	public void setInvisibleAllEdgesBut(final Set<Integer> edgeIds) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setInvisibleAllEdgesBut(edgeIds);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setInvisibleAllEdgesBut(edgeIds);
		}
	}
	
	@Override
	public void setInvisibleAllVerticesBut(final Set<Integer> vertexIds) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setInvisibleAllVerticesBut(vertexIds);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setInvisibleAllVerticesBut(vertexIds);
		}
	}
	
	@Override
	public void setInvisibleEdges(final Set<Integer> edgeIds) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setInvisibleEdges(edgeIds);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setInvisibleEdges(edgeIds);
		}		
	}
	
	@Override
	public void setInvisibleVertices(final Set<Integer> vertexIds) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setInvisibleVertices(vertexIds);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setInvisibleVertices(vertexIds);
		}
	}
	
	@Override
	public void setSelectionElements(final Set<Integer> lvsids, final Set<Integer> lesids) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setSelectionElements(lvsids, lesids);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setSelectionElements(lvsids, lesids);
		}		
	}
	
	@Override
	public void showAttributes(final Set<String> vertexAttr, final Set<String> edgeAttr) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						showAttributes(vertexAttr, edgeAttr);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.showAttributes(vertexAttr, edgeAttr);
		}	
	}
	
	@Override
	public void setColor4Vertex(final Color c, final Vertex v) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setColor4Vertex(c, v);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setColor4Vertex(c.toString(), v);
		}
	}
	
	@Override
	public void setColor4Edge(final Color c, final Edge e) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setColor4Edge(c, e);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setColor4Edge(c.toString(), e);
		}
	}
	
	@Override
	public void setShape4Vertex(final String shape, final Vertex v) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setShape4Vertex(shape, v);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setShape4Vertex(shape, v);
		}
	}
	
	@Override
	public void setShape4Edge(final String shape, final Edge e) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setShape4Edge(shape, e);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setShape4Edge(shape, e);
		}
	}
	
	@Override
	public void setStyle(final Map<String, Object> stylesheet) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setStyle(stylesheet);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setStyle(stylesheet);
		}
	}
	
	@Override
	public void setStyle(final String style, final Object value) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setStyle(style, value);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setStyle(style, value);
		}		
	}
		
//=============================================================================
//-----------------Methods for editing graph-----------------------------------	
	@Override
	public void setDirected(final boolean directed) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						setDirected(directed);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.setDirected(directed);
		}
	};
	
	@Override
	public void addVertex(final Vertex vertex) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						addVertex(vertex);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.addVertex(vertex);
		}
	}
	
	@Override
	public void addVertices(final Collection<Vertex> vertices) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						addVertices(vertices);
					}
				});
			} catch (Exception ex) {} 
		} else {
			sgv_graph_renderer.addVertices(vertices);
		}
	}
	
	@Override
	public void addEdge(final Edge edge) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						addEdge(edge);
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.addEdge(edge);
		}
	}
	
	@Override
	public void addEdges(final Collection<Edge> edges) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						addEdges(edges);
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.addEdges(edges);
		}
	}
	
	@Override
	public void addAttribute4Vertex(final Attribute attr, final Vertex vertex) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						addAttribute4Vertex(attr, vertex);
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.addAttribute4Vertex(attr, vertex);
		}
	}
	
	@Override
	public void addAttribute4Edge(final Attribute attr, final Edge edge) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						addAttribute4Edge(attr, edge);
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.addAttribute4Edge(attr, edge);
		}
	}
	
	@Override
	public int getGraphId() {
		return sgv_graph_renderer.getGraphId();
	}
	
	@Override
	public void setGraphId(int graphId) {
		sgv_graph_renderer.setGraphId(graphId);
	}
	
	@Override
	public int getGraphModelId() {
		return sgv_graph_renderer.getGraphModelId();
	}
	
	@Override
	public void setGraphModelId(int graphModelId) {
		sgv_graph_renderer.setGraphModelId(graphModelId);
	}

//=============================================================================
//-----------------Undo/Redo methods-------------------------------------------
	@Override
	public void undo() {
		sgv_graph_renderer.undo();
	}
	
	@Override
	public void redo() {
		sgv_graph_renderer.redo();
	}
	
//=============================================================================
//-----------------Panning-----------------------------------------------------
	@Override
	public boolean isPanning() {
		return sgv_graph_renderer.isPanning();
	};
	
	@Override
	public void setPanning(boolean panning) {
		sgv_graph_renderer.setPanning(panning);
	}
			
//=============================================================================
//-----------------Methods for adding observers to graph representation--------
	
	@Override
	public boolean addObserver(Observer o) {
		return sgv_graph_renderer.addObserver(o);
	}
	
	@Override
	public void removeAllObservers() {
		sgv_graph_renderer.removeAllObservers();
	}
	
	@Override
	public boolean removeObserver(Observer o) {
		return sgv_graph_renderer.removeObserver(o);
	}
	
	@Override
	public void addPopupMenuItem(final JMenuItem item) {
		if (!SwingUtilities.isEventDispatchThread()) {
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					addPopupMenuItem(item);
				}
			});
		} else {
			sgv_graph_renderer.addPopupMenuItem(item);
		}		
	}
	
	@Override
	public void removePopupMenuItem(final JMenuItem item) {
		if (!SwingUtilities.isEventDispatchThread()) {
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					removePopupMenuItem(item);
				}
			});
		} else {
			sgv_graph_renderer.removePopupMenuItem(item);
		}
	}
	
//=============================================================================
//-----------------Methods for scaling graph-----------------------------------
	@Override
	public void zoomIn() {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						zoomIn();
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.zoomIn();
		}
	}

	@Override
	public void zoomOut() {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						zoomOut();
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.zoomOut();
		}
	}

//=============================================================================
//-----------------Methods for algorithms--------------------------------------
	@Override
	public void showCriticalPath(final Vertex source, final Vertex target, final boolean maximum, final String attrName) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						showCriticalPath(source, target, maximum, attrName);
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.showCriticalPath(source, target, maximum, attrName);
		}	
	}
	
	@Override
	public void showCycles(final Vertex v) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						showCycles(v);
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.showCycles(v);
		}	
	}
	
	@Override
	public void showPaths(final Vertex source, final Vertex target) {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						showPaths(source, target);
					}
				});
			} catch (Exception ex) {}
		} else {
			sgv_graph_renderer.showPaths(source, target);
		}		
	}
	
//=============================================================================
//-----------------Access methods to low level components----------------------
	@Override
	public AMainGraphComponent getMainGraphComponents() {
		return sgv_graph_renderer;
	}

//=============================================================================
//-----------------PRIVATE METHODS---------------------------------------------
	private void init_components() {
		if (!SwingUtilities.isEventDispatchThread()) {
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						init_components();
					}
				});
			} catch (Exception ex) {
				MainManager.log.printException(ex);
			}
		} else {			
			sgv_graph_renderer = new JGraphRenderer(parent);
		}
	}
}
